/*
 * To change this template, choose Tools | Templates and open the template in the editor.
 */

package cz.muni.fi.xkadlec6.bp.regularExpression;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * The class stands for the node of the tree
 * 
 * @author Jana Kadlecova
 */
public class Node
{

	private String name;
	private boolean operation;
	private List<Node> children;
	private int id;

	public Node(String name, boolean operation, IDGenerator i)
	{
		this.name = name;
		this.operation = operation;
		this.children = new ArrayList<Node>();
		this.id = i.getID();
	}

	public Node(Node node, IDGenerator i)
	{
		this.name = node.getName();
		this.operation = node.isOperation();
		this.id = i.getID();
		this.children = new ArrayList<Node>();

		List<Node> nodes = node.getChildren();
		int k = nodes.size();

		switch (k)
		{
			case 1:
				Node n = new Node(nodes.get(0), i);
				this.addChildren(n);
				break;
			case 2:
				Node n1 = new Node(nodes.get(0), i);
				Node n2 = new Node(nodes.get(1), i);
				this.addChildren(n1, n2);
				break;
		}

	}

	public int getID()
	{
		return this.id;
	}

	public boolean isOperation()
	{
		return this.operation;
	}

	public String getName()
	{
		return this.name;
	}

	public void addChildren(Node left, Node right)
	{
		if (!this.isOperation())
		{
			throw new Error("Node,addChildren(): this node is not the operation, cannot be added any children");
		}
		if (this.getName().equals("*"))
		{
			throw new Error("Node.addChildren(): this node stands the iteration for, cannot be added two children");
		}
		if (!children.isEmpty())
		{
			throw new Error("Node.addChildren(): the children are added yet");
		}
		children.add(left);
		children.add(right);
	}

	public void addChildren(Node node)
	{
		if (!this.isOperation())
		{
			throw new Error("addChildren2");
		}
		if (!this.getName().equals("*"))
		{
			throw new Error("addChildren2");
		}
		if (!children.isEmpty())
		{
			throw new Error("addChildren2");
		}

		children.add(node);

	}

	public List<Node> getChildren()
	{
		return Collections.unmodifiableList(this.children);
	}

	@Override
	public String toString()
	{
		StringBuilder sb = new StringBuilder();
		if (!this.isOperation())
		{
			sb.append(this.stringToPlainText(this.name));
			return sb.toString();
		}
		else
		{
			if (this.getName().equals("*"))
			{
				sb.append("(");
				sb.append(this.children.get(0).toString());
				sb.append("*)");
			}
			else
			{
				sb.append("(");
				sb.append(this.children.get(0).toString());
				sb.append(this.name);
				sb.append(this.children.get(1).toString());
				sb.append(")");
			}
		}
		return sb.toString().replace("epsilon", "\\e");
	}

	public String toIS()
	{
		StringBuilder sb = new StringBuilder();
		if (!this.isOperation())
		{
			if (this.getName().length() > 1 && !this.getName().equals("\\0") && !this.getName().equals("\\o")
				&& !this.getName().equals("\\O"))
			{
				sb.append("\"" + this.stringToPlainText(this.getName()) + "\"");
			}
			else
			{
				sb.append(this.stringToPlainText(this.getName()));
			}
			return sb.toString();
		}
		else
		{
			if (this.getName().equals("*"))
			{
				sb.append("(");
				sb.append(this.children.get(0).toIS());
				sb.append("*)");
			}
			else
			{
				sb.append("(");
				sb.append(this.children.get(0).toIS());
				sb.append(this.name);
				sb.append(this.children.get(1).toIS());
				sb.append(")");
			}
		}
		return sb.toString().replace("epsilon", "\\e");
	}

	public String toLaTeX()
	{
		StringBuilder sb = new StringBuilder();
		if (!this.isOperation())
		{
			String s = (this.getName()).replace("epsilon", "\\varepsilon").replace("\\0", "\\emptyset");
			sb.append(s);
			return sb.toString();
		}
		else
		{
			if (this.getName().equals("*"))
			{
				sb.append("(");
				sb.append(this.children.get(0).toLaTeX());
				sb.append("^*)");
			}
			else
			{
				sb.append("(");
				sb.append(this.children.get(0).toLaTeX());
				sb.append(this.name);
				sb.append(this.children.get(1).toLaTeX());
				sb.append(")");
			}
		}
		return sb.toString();
	}

	@Override
	public boolean equals(Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (!(o instanceof Node))
		{
			return false;
		}
		Node n = (Node) o;
		if (n.getID() == this.getID() && n.getName().equals(n.getName()) && n.isOperation() == this.isOperation())
		{
			if (this.getChildren().size() != n.getChildren().size())
			{
				return false;
			}
			for (int i = 0; i < this.getChildren().size(); i++)
			{
				if (!this.getChildren().get(i).equals(n.getChildren().get(i)))
				{
					return false;
				}
			}
			return true;
		}
		return false;
	}

	@Override
	public int hashCode()
	{
		int hash = 7;
		hash = 17 * hash + (this.name != null ? this.name.hashCode() : 0);
		hash = 17 * hash + (this.operation ? 1 : 0);
		hash = 17 * hash + (this.children != null ? this.children.hashCode() : 0);
		hash = 17 * hash + this.id;
		return hash;
	}

	/**
	 * string without some characters: '_' and '{' and '}'
	 * 
	 * @param s
	 *            string
	 * @return string without some characters: '_' and '{' and '}'
	 */
	private String stringToPlainText(String s)
	{
		return s.replace("_{", "").replace("}", "");
	}

}
